package com.atguigu.daijia.map.service.impl;

import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.common.constant.SystemConstant;
import com.atguigu.daijia.common.result.Result;
import com.atguigu.daijia.driver.client.DriverInfoFeignClient;
import com.atguigu.daijia.map.service.LocationService;
import com.atguigu.daijia.model.entity.driver.DriverSet;
import com.atguigu.daijia.model.form.map.SearchNearByDriverForm;
import com.atguigu.daijia.model.form.map.UpdateDriverLocationForm;
import com.atguigu.daijia.model.vo.map.NearByDriverVo;
import io.lettuce.core.GeoRadiusStoreArgs;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.mongodb.core.query.GeoCommand;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.domain.geo.GeoLocation;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
@RequiredArgsConstructor
@SuppressWarnings({"unchecked", "rawtypes"})
public class LocationServiceImpl implements LocationService {
    private final RedisTemplate redisTemplate;

    private final DriverInfoFeignClient driverInfoFeignClient;

    /**
     * 更新司机位置信息
     *
     * @param updateDriverLocationForm
     * @return
     */
    @Override
    public Boolean updateDriverLocation(UpdateDriverLocationForm updateDriverLocationForm) {
        Point point = new Point(updateDriverLocationForm.getLongitude().doubleValue(),
                                updateDriverLocationForm.getLatitude().doubleValue());
        redisTemplate.opsForGeo().add(RedisConstant.DRIVER_GEO_LOCATION,
                                    point,updateDriverLocationForm.getDriverId().toString());
        return true;
    }

    /**
     * 删除司机位置信息
     *
     * @param driverId
     * @return
     */
    @Override
    public Boolean removeDriverLocation(Long driverId) {
        redisTemplate.opsForGeo().remove(RedisConstant.DRIVER_GEO_LOCATION,driverId.toString());
        return true;
    }

    /**
     * 搜索附近满足条件的司机
     *
     * @param searchNearByDriverForm
     * @return
     */
    @Override
    public List<NearByDriverVo> searchNearByDriver(SearchNearByDriverForm searchNearByDriverForm) {
        //默认搜索5km内满足条件的司机
        Point point = new Point(searchNearByDriverForm.getLongitude().doubleValue(),
                searchNearByDriverForm.getLatitude().doubleValue());
        Distance distance = new Distance(SystemConstant.NEARBY_DRIVER_RADIUS,
                RedisGeoCommands.DistanceUnit.KILOMETERS);
        Circle circle = new Circle(point, distance);

        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
                .newGeoRadiusArgs()
                .includeDistance()
                .includeDistance()
                .sortDescending();

        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = redisTemplate.opsForGeo().
                radius(RedisConstant.DRIVER_GEO_LOCATION, circle, args);

        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> resultList = geoResults.getContent();
        ArrayList<NearByDriverVo> nearByDriverVos = new ArrayList<>();

        if(!CollectionUtils.isEmpty(resultList)){
            Iterator<GeoResult<RedisGeoCommands.GeoLocation<String>>> iterator = resultList.iterator();
            while(iterator.hasNext()){
                GeoResult<RedisGeoCommands.GeoLocation<String>> result = iterator.next();
                //查询司机设置信息
                Long driverId = Long.valueOf(result.getContent().getName());
                Result<DriverSet> driverSetResult = driverInfoFeignClient.getDriverSet(driverId);
                DriverSet driverSet = driverSetResult.getData();

                //司机能接受的与乘客的最短距离
                BigDecimal acceptDistance = driverSet.getAcceptDistance();
                //司机能接受的最短订单距离
                BigDecimal orderDistance = driverSet.getOrderDistance();
                //当前司机与乘客的距离
                double dis = result.getDistance().getValue();
                BigDecimal inDistance = new BigDecimal(dis).setScale(2, RoundingMode.HALF_UP);
                if(acceptDistance.doubleValue() != 0
                        && acceptDistance.doubleValue() < inDistance.doubleValue()){
                    continue;
                }
                if(orderDistance.doubleValue() != 0
                        && orderDistance.doubleValue() < searchNearByDriverForm.getMileageDistance().doubleValue()){
                    continue;
                }
                NearByDriverVo nearByDriverVo = new NearByDriverVo();
                nearByDriverVo.setDriverId(driverId);
                nearByDriverVo.setDistance(inDistance);
                nearByDriverVos.add(nearByDriverVo);
            }
        }
        return nearByDriverVos;
    }
}
